]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
shell/app: Explicitly handle (X11) fallback icon changes
authorFlorian Müllner <fmuellner@gnome.org>
Fri, 12 Mar 2021 22:10:42 +0000 (23:10 +0100)
committerMarge Bot <marge-bot@gnome.org>
Sun, 14 Mar 2021 20:36:41 +0000 (20:36 +0000)
Since commit 770231, StImageContent implements the GIcon interface, which
allowed us to represent all application icons as GIcon (app-info, X11 icon
property or themed fallback icon).

While that change made for a nicer ShellApp API, it did introduce a
conceptual issue in st_texture_cache_bind_cairo_surface_property():
GIcons usually represent static icons, while the ClutterContent
returned by that method updates automatically when the bound property
changes.

Address this by tracking the MetaWindow:icon property in ShellApp, and
update the fallback icon when it changes. With that, a GIcon object
always represents the same icon, and any icon change is reflected
by a corresponding GIcon change.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1761>

src/shell-app.c

index d86b05a22d25bb531dae2d75e19fb790cf302686..62ba2ec73a8d358ea681a1cb07f54631569d9e4c 100644 (file)
@@ -38,6 +38,8 @@ typedef struct {
   /* Signal connection to dirty window sort list on workspace changes */
   gulong workspace_switch_id;
 
+  gulong icon_changed_id;
+
   GSList *windows;
 
   guint interesting_windows;
@@ -185,6 +187,32 @@ window_backed_app_get_window (ShellApp     *app)
     return NULL;
 }
 
+static GIcon *
+x11_window_create_fallback_gicon (MetaWindow *window)
+{
+  StTextureCache *texture_cache;
+  cairo_surface_t *surface;
+
+  g_object_get (window, "icon", &surface, NULL);
+
+  texture_cache = st_texture_cache_get_default ();
+  return st_texture_cache_load_cairo_surface_to_gicon (texture_cache, surface);
+}
+
+static void
+on_window_icon_changed (GObject          *object,
+                        const GParamSpec *pspec,
+                        gpointer          user_data)
+{
+  MetaWindow *window = META_WINDOW (object);
+  ShellApp *app = user_data;
+
+  g_clear_object (&app->fallback_icon);
+  app->fallback_icon = x11_window_create_fallback_gicon (window);
+
+  g_object_notify (G_OBJECT (app), "icon");
+}
+
 /**
  * shell_app_get_icon:
  *
@@ -215,10 +243,10 @@ shell_app_get_icon (ShellApp *app)
   if (window &&
       meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_X11)
     {
-      app->fallback_icon =
-        st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
-                                                      G_OBJECT (window),
-                                                      "icon");
+      app->fallback_icon = x11_window_create_fallback_gicon (window);
+      app->running_state->icon_changed_id =
+        g_signal_connect (G_OBJECT (window),
+                         "notify::icon", G_CALLBACK (on_window_icon_changed), app);
     }
   else
     {
@@ -240,15 +268,13 @@ ClutterActor *
 shell_app_create_icon_texture (ShellApp   *app,
                                int         size)
 {
-  GIcon *icon;
   ClutterActor *ret;
 
   ret = st_icon_new ();
   st_icon_set_icon_size (ST_ICON (ret), size);
   st_icon_set_fallback_icon_name (ST_ICON (ret), "application-x-executable");
 
-  icon = shell_app_get_icon (app);
-  st_icon_set_gicon (ST_ICON (ret), icon);
+  g_object_bind_property (app, "icon", ret, "gicon", G_BINDING_SYNC_CREATE);
 
   if (shell_app_is_window_backed (app))
     st_widget_add_style_class_name (ST_WIDGET (ret), "fallback-app-icon");
@@ -1121,6 +1147,8 @@ _shell_app_remove_window (ShellApp   *app,
   g_signal_handlers_disconnect_by_func (window, G_CALLBACK(shell_app_on_skip_taskbar_changed), app);
   app->running_state->windows = g_slist_remove (app->running_state->windows, window);
 
+  g_clear_signal_handler (&app->running_state->icon_changed_id, window);
+
   if (!meta_window_is_skip_taskbar (window))
     app->running_state->interesting_windows--;
   shell_app_sync_running_state (app);